use std::thread::spawn;
use std::time::Duration;

use message_io::network::Transport;
use message_io::node::{self, NodeEvent};

use tools::tcp_tokio;
use tools::tcp_tokio::{MessageHandler, NetEvent, TcpHandler};

pub fn main() {
    spawn(move || {
        server_fn();
    });
    spawn(move || {
        client_fn();
    });
    std::thread::park();
}

pub fn server_fn() {
    let mut client = Client { handler: None };
    spawn(move || {
        tcp_tokio::Builder::new().build(1080, move |event| match event {
            NetEvent::Connected(tcp_handler) => {
                client.on_open(tcp_handler);
            }
            NetEvent::Message(data) => {
                client.on_message(&data);
            }
            NetEvent::Disconnected => {
                client.on_close();
            }
        });
    });
}

#[derive(Default)]
struct Client {
    pub handler: Option<TcpHandler>,
}

impl Clone for Client {
    fn clone(&self) -> Self {
        Self { handler: None }
    }
}

impl MessageHandler for Client {
    fn on_open(&mut self, tcp_handler: TcpHandler) {
        self.handler = Some(tcp_handler);
        println!(
            "new tcp client connect!{}",
            self.handler.as_ref().unwrap().0.peer_addr().unwrap()
        );
    }

    fn on_close(&mut self) {
        println!(
            "tcp client close!{}",
            self.handler.as_ref().unwrap().0.peer_addr().unwrap()
        );
    }

    fn on_message(&mut self, mess: &[u8]) {
        println!("rec mess from client{:?}", mess);
        self.handler.as_mut().unwrap().send(mess);
    }
}

pub fn client_fn() {
    let (handler, listener) = node::split();

    // You can change the transport to Udp or Ws (WebSocket).
    let (server, _) = handler
        .network()
        .connect(Transport::FramedTcp, "127.0.0.1:1080")
        .unwrap();

    listener.for_each(move |event| match event {
        NodeEvent::Network(net_event) => match net_event {
            message_io::network::NetEvent::Connected(_endpoint, _ok) => {
                handler.signals().send(Signal::Greet)
            }
            message_io::network::NetEvent::Accepted(_, _) => unreachable!(), // Only generated by listening
            message_io::network::NetEvent::Message(_endpoint, data) => {
                println!("Received: {}", String::from_utf8_lossy(data));
            }
            message_io::network::NetEvent::Disconnected(_endpoint) => (),
        },
        NodeEvent::Signal(signal) => match signal {
            Signal::Greet => {
                // computed every second
                handler.network().send(server, "Hello server!".as_bytes());
                handler
                    .signals()
                    .send_with_timer(Signal::Greet, Duration::from_secs(1));
            }
        },
    });
}
enum Signal {
    Greet,
    // Any other app event here.
}
